前言 提到Android的多线程机制,除了我们常用的Thread来实现异步任务之外,还有
AsyncTask :封装了线程池和Handler,主要为了子线程更新UI;
HandlerThread :一个已经拥有了Looper的线程类,内部可以直接使用Handler;
IntentService :一个内部采用HandlerThread来执行任务的Service服务,任务执行完毕后会自动退出;
今天我们来根据平时的使用方式来分析一下第三个IntentSevice到底是什么怎么实现的?
IntentService的使用 IntentService继承了Service并且它本身是一个抽象类 ,因此使用它必须创建它的子类才能使用。所以这里我们自定义一个MyIntentService,来处理异步任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService" ; private boolean isRunning = true ; private int count = 0 ; public MyIntentService () { super ("MyIntentService" ); } @Override public void onCreate () { super .onCreate(); } @Override protected void onHandleIntent (Intent intent) { try { Log.i(TAG, intent.getStringExtra("params" ) + ", 线程id:" + Thread.currentThread().getId()); Thread.sleep(1000 ); isRunning = true ; count = 0 ; while (isRunning) { count++; Log.i(TAG, "MyIntentService 线程运行中..." + count); if (count >= 100 ) { isRunning = false ; } Thread.sleep(50 ); } } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onDestroy () { super .onDestroy(); } }
然后启动服务之前别忘了在manifest文件中注册这个Service:
1 2 <service android:name=".service.MyIntentService" />
最后是启动服务,就和普通Service一样启动:1 2 3 4 Intent intent= new Intent(getActivity(), MyIntentService.class); intent.putExtra("params" , "testString..." ); getActivity().startService(intent);
到此,通过IntentService执行的异步任务已经开始执行了,当执行完毕之后它会自动停止而不用我们手动操作。
当这个MyIntentService启动之后,我们看到它接收到了消息并打印出了传递过去的intent参数,同时显示onHandlerIntent方法执行的线程ID并非主线程 ,也就是说它果真开了一个额外的线程,什么时候开启的呢?我们进入IntentService源码看看。
IntentService源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler (Looper looper) { super (looper); } @Override public void handleMessage (Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } public IntentService (String name) { super (); mName = name; } public void setIntentRedelivery (boolean enabled) { mRedelivery = enabled; } @Override public void onCreate () { super .onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]" ); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart (@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } @Override public int onStartCommand (@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy () { mServiceLooper.quit(); } @Override @Nullable public IBinder onBind (Intent intent) { return null ; } @WorkerThread protected abstract void onHandleIntent (@Nullable Intent intent) ; }
代码还是相当的简洁的,首先通过定义我们可以知道IntentService是一个Service,并且是一个抽象类,所以我们在继承IntentService的时候需要实现其抽象方法:onHandlerIntent。
1. 启动 IntentService 为什么不需要新建线程? 我们来看看它的onCreate()函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private volatile ServiceHandler mServiceHandler;@Override public void onCreate () { super .onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]" ); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
我们可以发现其内部定义一个HandlerThread(本质上是一个含有消息队列的线程)。然后用成员变量维护其Looper和Handler,由于其Handler(也就是mServiceHandler对象)关联着这个HandlerThread的Looper对象,所以这个ServiceHandler
的handleMessage方法在HandlerThread线程中执行 。
然后我们发现其onStartCommand方法就是调用的其onStart方法,具体看一下其onStart方法:
1 2 3 4 5 6 7 @Override public void onStart (@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
很简单就是将startId和启动时接受到的intent对象传递到ServiceHandler的消息队列中处理,那么我们具体看一下ServiceHandler的处理逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 private final class ServiceHandler extends Handler { public ServiceHandler (Looper looper) { super (looper); } @Override public void handleMessage (Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } }
可以看到起handleMessage方法内部执行了两个逻辑:
一个是调用了其onHandlerIntent()
抽象方法,在子线程中执行。
二是调用了stopSelf()
方法,这里需要注意的是stopSelf方法传递了msg.arg1
参数,从刚刚的onStart方法我们可以知道我们传递了startId
,这是由于service可以启动多次,可以传递N次消息 ,当IntentService的消息队列中含有消息时调用stopSelf(startId)并不会立即stop自己,只有当消息队列中最后一个消息被执行完成时才会真正的stop自身 。
2. 为什么不建议通过 bindService() 启动 IntentService? 我们看IntentService的onBind()
方法:
1 2 3 4 @Override public IBinder onBind (Intent intent) { return null ; }
IntentService 源码中的 onBind()
默认返回 null,不适合 bindService()
启动服务,如果你执意要 bindService()
来启动 IntentService,可能因为你想通过 Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,这样 onHandleIntent() 就不会被回调 ,相当于在你使用 Service 而不是 IntentService。
总结 IntentService 是继承自 Service 并处理异步请求的一个抽象类 ,在 IntentService 内有一个工作线程来处理耗时操作,当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,执行完自动结束。
IntentService有以下特点:
1). 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。 2). 创建了一个工作队列,来逐个发送intent给onHandleIntent()。 3). 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。 4). 默认实现的onBind()返回null 5). 默认实现的onStartCommand()的目的是将intent插入到工作队列中
继承IntentService的类至少要实现两个函数:构造函数 和onHandleIntent() 函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数。
参考资料